package com.bocloud.cmp.service.resource;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.dao.CloudServerDao;
import com.bocloud.cmp.dao.CloudVendorDao;
import com.bocloud.cmp.dao.ClusterDao;
import com.bocloud.cmp.dao.HostSystemDao;
import com.bocloud.cmp.dao.SnapshotDao;
import com.bocloud.cmp.driver.providers.intf.ClusterProvider;
import com.bocloud.cmp.driver.providers.intf.HostProvider;
import com.bocloud.cmp.entity.resource.CloudVendor;
import com.bocloud.cmp.entity.resource.Cluster;
import com.bocloud.cmp.entity.resource.HostSystem;
import com.bocloud.cmp.interfaces.resource.ClusterService;
import com.bocloud.cmp.model.ClusterBean;
import com.bocloud.cmp.model.ClusterOperateModel;
import com.bocloud.cmp.model.HostOperateModel;
import com.bocloud.cmp.service.model.OperateResult;
import com.bocloud.cmp.service.utils.ResourceEventPublisher;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.Sign;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.coordinator.harmony.HarmonyLock;
import com.bocloud.coordinator.harmony.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

@Service("clusterService")
public class ClusterServiceImpl implements ClusterService {

	private static final Logger logger = LoggerFactory.getLogger(ClusterServiceImpl.class);
	@Autowired
	private ClusterDao clusterDao;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private CloudVendorDao cloudVendorDao;
	@Autowired
	private ClusterProvider clusterProvider;
	@Autowired
	private HostProvider hostProvider;
	@Autowired
	private HostSystemDao hostSystemDao;
	@Autowired
	private CloudServerDao cloudServerDao;
	@Autowired
	private SnapshotDao snapshotDao;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;

	@Override
	public BsmResult list(int page, int rows, List<Param> params, Map<String, String> sorter, Boolean simple) {
		GridBean gridBean = null;
		try {
			if (null == params) {
				params = Lists.newArrayList();
			}
			if (null == sorter) {
				sorter = Maps.newHashMap();
			}
			sorter.put("gmtCreate", Common.ONE);
			int total = this.clusterDao.count(params);
			if (simple) {
				List<SimpleBean> beans = this.clusterDao.list(params, sorter);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				List<Cluster> list = this.clusterDao.list(page, rows, params, sorter);
				for (Cluster cluster : list) {
					params.clear();
					params.add(new Param(MapTools.simpleMap("clusterId", cluster.getId()), Sign.EQ));
					List<SimpleBean> hosts = hostSystemDao.list(params, null);
					int vmNum = 0;
					int templateNum = 0;
					for (SimpleBean host : hosts) {
						params.clear();
						params.add(new Param(MapTools.simpleMap("hostId", host.getId()), Sign.EQ));
						vmNum += cloudServerDao.count(params);
						params.add(new Param(MapTools.simpleMap("isTemplate", 1), Sign.EQ));
						templateNum += cloudServerDao.count(params);
					}
					cluster.setHostNum(hosts.size());
					cluster.setVmNum(vmNum - templateNum);
					cluster.setTemplateNum(templateNum);
				}
				gridBean = GridHelper.getBean(page, rows, total, list);
			}
			return new BsmResult(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("Query cluster list fail:", e);
			return new BsmResult(false, "查询失败");
		}
	}

	@Override
	public BsmResult create(ClusterOperateModel model, Long userId) {
		try {
			CloudVendor vendor = cloudVendorDao.query(model.getVendorId());
			if (null == vendor) {
				return new BsmResult(false, "获取运供应商失败");
			}
			BsmResult result = clusterProvider.create(vendor.getUuid(), model);
			if (result.isSuccess()) {
				// 同步集群
				String content = JSONObject.toJSONString(result.getData());
				Cluster cluster = JSONObject.parseObject(content, Cluster.class);
				cluster.setMenderId(userId);
				cluster.setCreaterId(userId);
				cluster.setVdcId(model.getVdcId());
				cluster.setVendorId(model.getVendorId());
				clusterDao.save(cluster);
			}
			return new BsmResult(result.isSuccess(), result.getMessage());
		} catch (Exception e) {
			logger.error("create cluster error", e);
			return new BsmResult(false, "创建集群失败");
		}
	}

	@Override
	public BsmResult modify(ClusterBean bean, Long userId) {
		String path = Cluster.class.getSimpleName() + "_" + bean.getId();
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			Cluster cluster = this.clusterDao.query(bean.getId());
			if (null == cluster) {
				logger.warn("Cluster does not exist!");
				return new BsmResult(false, "数据不存在");
			}
			BeanUtils.copyProperties(bean, cluster);
			cluster.setMenderId(userId);
			this.clusterDao.update(cluster);
			return new BsmResult(true, "修改成功");
		} catch (Exception e) {
			logger.error("Modify cluster fail:", e);
			return new BsmResult(false, "修改失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult remove(Long id, Long userId) {
		String path = Cluster.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			Cluster cluster = this.clusterDao.query(id);
			if (null == cluster) {
				logger.warn("Cluster does not exist!");
				return new BsmResult(false, "数据不存在");
			}
			CloudVendor vendor = this.cloudVendorDao.query(cluster.getVendorId());
			if (null == vendor) {
				logger.warn("Vendor does not exist!");
				return new BsmResult(false, "获取运供应商失败");
			}
			new Thread(new Runnable() {
				@Override
				public void run() {
					// 删除vmware上的集群
					ClusterOperateModel model = new ClusterOperateModel();
					model.setClusterName(cluster.getName());
					model.setVdcName(cluster.getVdcName());
					String operate = vendor.getType().toLowerCase() + ".cluster";
					BsmResult result = clusterProvider.remove(vendor.getUuid(), model);
					if (result.isSuccess()) {
						try {
							List<Param> params = Lists.newArrayList();
							// 查出集群下的宿主机
							params.add(new Param(MapTools.simpleMap("clusterId", id), Sign.EQ));
							List<SimpleBean> hosts = hostSystemDao.list(params, null);
							for (SimpleBean host : hosts) {
								params.clear();
								params.add(new Param(MapTools.simpleMap("hostId", host.getId()), Sign.EQ));
								// 查出宿主机下的虚拟机
								List<SimpleBean> servers = cloudServerDao.list(params, null);
								for (SimpleBean server : servers) {
									// 删除宿主机下的快照
									snapshotDao.removeByVm(server.getId(), userId);
								}
								// 删除宿主机下的虚拟机
								cloudServerDao.removeByHost(host.getId(), userId);
							}
							// 删除集群下的宿主机
							hostSystemDao.deleteByCluster(id, userId);
							clusterDao.remove(id, userId);
						} catch (Exception e) {
							logger.error("删除集群失败", e);
							resourceEventPublisher.send(new OperateResult(false, "集群删除失败", operate,
									MapTools.simpleMap("vendorId", vendor.getId())));
						}
					}
					resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
							MapTools.simpleMap("vendorId", vendor.getId())));
				}
			}).start();
			return new BsmResult(true, "删除任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("Remove cluster error:", e);
			return new BsmResult(false, "删除失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult detail(Long id) {
		try {
			Cluster cluster = this.clusterDao.query(id);
			if (null == cluster) {
				return new BsmResult(false, "数据不存在");
			}
			List<Param> params = Lists.newArrayList();
			params.add(new Param(MapTools.simpleMap("clusterId", id), Sign.EQ));
			List<HostSystem> hosts = hostSystemDao.list(1, Integer.MAX_VALUE, params, null);
			int vmNum = 0;
			int templateNum = 0;
			int cpuCore = 0;
			Long cpuTotal = 0L;
			Long memTotal = 0L;
			for (HostSystem host : hosts) {
				params.clear();
				params.add(new Param(MapTools.simpleMap("hostId", host.getId()), Sign.EQ));
				vmNum += cloudServerDao.count(params);
				params.add(new Param(MapTools.simpleMap("isTemplate", 1), Sign.EQ));
				templateNum += cloudServerDao.count(params);
				cpuCore += host.getCpuCore();
				cpuTotal += host.getCpuTotal();
				memTotal += host.getMemTotal();
			}
			cluster.setHostNum(hosts.size());
			cluster.setVmNum(vmNum - templateNum);
			cluster.setTemplateNum(templateNum);
			cluster.setCpuCore(cpuCore);
			cluster.setCpuTotal(cpuTotal);
			cluster.setMemTotal(memTotal);
			return new BsmResult(true, cluster, "查询详情成功");
		} catch (Exception e) {
			logger.error("Get cluster error：", e);
			return new BsmResult(false, "查询详情失败");
		}
	}

	@Override
	public BsmResult moveHost(ClusterOperateModel model, Long userId) {
		String path = Cluster.class.getSimpleName() + "_" + model.getClusterId();
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			Cluster cluster = this.clusterDao.query(model.getClusterId());
			if (null == cluster) {
				return new BsmResult(false, "集群不存在！");
			}
			CloudVendor vendor = cloudVendorDao.query(model.getVendorId());
			if (null == vendor) {
				return new BsmResult(false, "获取运供应商失败");
			}
			List<Long> hosts = model.getHosts();
			List<String> names = Lists.newArrayList();
			List<HostSystem> hostSystems = Lists.newArrayList();
			if (!ListTool.isEmpty(hosts)) {
				for (Long host : hosts) {
					HostSystem hostSystem = hostSystemDao.query(host);
					// 宿主机在集群中并且没有进入维护模式的，不可移动
					if (null != hostSystem.getClusterId() && !hostSystem.isMaintain() && hostSystem.isConnected()) {
						continue;
					}
					names.add(hostSystem.getName());
					hostSystems.add(hostSystem);
				}
			}
			HostOperateModel operateModel = new HostOperateModel();
			operateModel.setVdcName(model.getVdcName());
			operateModel.setClusterName(model.getClusterName());
			operateModel.setHosts(names);
			BsmResult result = hostProvider.moveTo(vendor.getUuid(), null, operateModel);
			if (result.isSuccess()) {
				if (StringUtils.isEmpty(model.getClusterName())) {
					for (HostSystem hostSystem : hostSystems) {
						hostSystem.setMenderId(userId);
						hostSystem.setClusterId(null);
						this.hostSystemDao.update(hostSystem);
					}
				} else {
					for (HostSystem hostSystem : hostSystems) {
						hostSystem.setMenderId(userId);
						hostSystem.setClusterId(model.getClusterId());
						this.hostSystemDao.update(hostSystem);
					}
				}
			}
			return result;
		} catch (Exception e) {
			logger.error("add host exception", e);
			return new BsmResult(false, "移动失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

}
